<!DOCTYPE HTML>
<html lang="zh-Hans" class="sidebar-visible no-js light">
    <head>
        <!-- Book generated using mdBook -->
        <meta charset="UTF-8">
        <title>走进 Tokio 的异步世界 - Rust 优秀博文</title>


        <!-- Custom HTML head -->
        
        <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
        <meta name="description" content="">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta name="theme-color" content="#ffffff" />

        <link rel="icon" href="../../favicon.svg">
        <link rel="shortcut icon" href="../../favicon.png">
        <link rel="stylesheet" href="../../css/variables.css">
        <link rel="stylesheet" href="../../css/general.css">
        <link rel="stylesheet" href="../../css/chrome.css">
        <link rel="stylesheet" href="../../css/print.css" media="print">

        <!-- Fonts -->
        <link rel="stylesheet" href="../../FontAwesome/css/font-awesome.css">
        <link rel="stylesheet" href="../../fonts/fonts.css">

        <!-- Highlight.js Stylesheets -->
        <link rel="stylesheet" href="../../highlight.css">
        <link rel="stylesheet" href="../../tomorrow-night.css">
        <link rel="stylesheet" href="../../ayu-highlight.css">

        <!-- Custom theme stylesheets -->

    </head>
    <body>
        <!-- Provide site root to javascript -->
        <script type="text/javascript">
            var path_to_root = "../../";
            var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
        </script>

        <!-- Work around some values being stored in localStorage wrapped in quotes -->
        <script type="text/javascript">
            try {
                var theme = localStorage.getItem('mdbook-theme');
                var sidebar = localStorage.getItem('mdbook-sidebar');

                if (theme.startsWith('"') && theme.endsWith('"')) {
                    localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
                }

                if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
                    localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
                }
            } catch (e) { }
        </script>

        <!-- Set the theme before any content is loaded, prevents flash -->
        <script type="text/javascript">
            var theme;
            try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
            if (theme === null || theme === undefined) { theme = default_theme; }
            var html = document.querySelector('html');
            html.classList.remove('no-js')
            html.classList.remove('light')
            html.classList.add(theme);
            html.classList.add('js');
        </script>

        <!-- Hide / unhide sidebar before it is displayed -->
        <script type="text/javascript">
            var html = document.querySelector('html');
            var sidebar = 'hidden';
            if (document.body.clientWidth >= 1080) {
                try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
                sidebar = sidebar || 'visible';
            }
            html.classList.remove('sidebar-visible');
            html.classList.add("sidebar-" + sidebar);
        </script>

        <nav id="sidebar" class="sidebar" aria-label="Table of contents">
            <div class="sidebar-scrollbox">
                <ol class="chapter"><li class="chapter-item expanded "><a href="../../empty.html"><strong aria-hidden="true">1.</strong> 类型系统</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../01_类型系统/Rust_Concept_Clarification_Deref_vs_AsRef_vs_Borrow_vs_Cow/Rust_Concept_Clarification_Deref_vs_AsRef_vs_Borrow_vs_Cow.html"><strong aria-hidden="true">1.1.</strong> Rust Concept Clarification Deref vs AsRef vs Borrow vs Cow</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/Rust_Concept_Clarification_Deref_vs_AsRef_vs_Borrow_vs_Cow/Deref_AsRef_Borrow_Cow释义.html"><strong aria-hidden="true">1.2.</strong> Deref AsRef Borrow Cow 释义</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/Rust的Borrow和AsRef：让你的代码用起来像呼吸一样自然/Rust的Borrow和AsRef：让你的代码用起来像呼吸一样自然.html"><strong aria-hidden="true">1.3.</strong> Rust的Borrow和AsRef：让你的代码用起来像呼吸一样自然</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/Rust的Cow类型有什么用？详解Cow及其用途/Rust的Cow类型有什么用？详解Cow及其用途.html"><strong aria-hidden="true">1.4.</strong> Rust的Cow类型有什么用？详解Cow及其用途</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/判别Fn、FnMut、FnOnce的标准/判别Fn、FnMut、FnOnce的标准.html"><strong aria-hidden="true">1.5.</strong> 判别Fn、FnMut、FnOnce的标准</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/一行代码告诉你内部可变性的真相(UnsafeCell)/一行代码告诉你内部可变性的真相(UnsafeCell).html"><strong aria-hidden="true">1.6.</strong> 一行代码告诉你内部可变性的真相(UnsafeCell)</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/Tour_of_Rust's_Standard_Library_Traits/Tour_of_Rust's_Standard_Library_Traits.html"><strong aria-hidden="true">1.7.</strong> Tour of Rust's Standard Library Traits</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/逆变、协变与子类型，以及Rust/逆变、协变与子类型，以及Rust.html"><strong aria-hidden="true">1.8.</strong> 逆变、协变与子类型，以及Rust</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/Rust自引用结构、Pin与Unpin/Rust自引用结构、Pin与Unpin.html"><strong aria-hidden="true">1.9.</strong> Rust自引用结构、Pin与Unpin</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/为什么Rust需要Pin,Unpin/为什么Rust需要Pin,Unpin.html"><strong aria-hidden="true">1.10.</strong> 译：为什么 Rust 需要 Pin, Unpin ？</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/定海神针Pin和Unpin/定海神针Pin和Unpin.html"><strong aria-hidden="true">1.11.</strong> 译：定海神针 Pin 和 Unpin</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/sizedness-in-rust/sizedness-in-rust.html"><strong aria-hidden="true">1.12.</strong> Sizedness in Rust</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/Rust生命周期集大成者PhantomData〈T〉/Rust生命周期集大成者PhantomData〈T〉.html"><strong aria-hidden="true">1.13.</strong> Rust生命周期集大成者 PhantomData&lt;T&gt;</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/数据库表达式执行的黑魔法：用Rust做类型体操/数据库表达式执行的黑魔法：用Rust做类型体操_Part_0.html"><strong aria-hidden="true">1.14.</strong> 数据库表达式执行的黑魔法：用Rust做类型体操 Part 0</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/数据库表达式执行的黑魔法：用Rust做类型体操/数据库表达式执行的黑魔法：GAT实现引用类型关联_Part_1.html"><strong aria-hidden="true">1.15.</strong> 数据库表达式执行的黑魔法：GAT实现引用类型关联 Part 1</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/数据库表达式执行的黑魔法：用Rust做类型体操/数据库表达式执行的黑魔法：用HRTB写bound_Part_2.html"><strong aria-hidden="true">1.16.</strong> 数据库表达式执行的黑魔法：用HRTB写bound Part 2</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/数据库表达式执行的黑魔法：用Rust做类型体操/数据库表达式执行的黑魔法：用Rust做类型体操之用宏展开重复代码_Part_3_&_4.html"><strong aria-hidden="true">1.17.</strong> 数据库表达式执行的黑魔法：用Rust做类型体操之用宏展开重复代码 Part 3 & 4</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/数据库表达式执行的黑魔法：用Rust做类型体操/数据库表达式执行的黑魔法：与Rust编译器斗智斗勇之表达式向量化_Part_5_&_6.html"><strong aria-hidden="true">1.18.</strong> 数据库表达式执行的黑魔法：与Rust编译器斗智斗勇之表达式向量化 Part 5 & 6</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/数据库表达式执行的黑魔法：用Rust做类型体操/数据库表达式执行的黑魔法：在Rust中用宏关联逻辑类型和实际类型_Part_7.html"><strong aria-hidden="true">1.19.</strong> 数据库表达式执行的黑魔法：在Rust中用宏关联逻辑类型和实际类型 Part 7</a></li></ol></li><li class="chapter-item expanded "><a href="../../empty.html"><strong aria-hidden="true">2.</strong> 生命周期</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../02_生命周期/Rust中的生命周期——从StrSplit实例说开去/Rust中的生命周期——从StrSplit实例说开去.html"><strong aria-hidden="true">2.1.</strong> Rust中的生命周期——从StrSplit实例说开去</a></li><li class="chapter-item expanded "><a href="../../02_生命周期/与ChatGPT深度对话来学Rust生命周期/与ChatGPT深度对话来学Rust生命周期.html"><strong aria-hidden="true">2.2.</strong> 与ChatGPT深度对话来学Rust生命周期</a></li><li class="chapter-item expanded "><a href="../../02_生命周期/进击的Rust生命周期——early_bound与late_bound（1）/进击的Rust生命周期——early_bound与late_bound（1）.html"><strong aria-hidden="true">2.3.</strong> 进击的Rust生命周期——early_bound与late_bound（1）</a></li><li class="chapter-item expanded "><a href="../../02_生命周期/进击的Rust生命周期——early_bound与late_bound（2）/进击的Rust生命周期——early_bound与late_bound（2）.html"><strong aria-hidden="true">2.4.</strong> 进击的Rust生命周期——early_bound与late_bound（2）</a></li><li class="chapter-item expanded "><a href="../../02_生命周期/进击的Rust生命周期——一力降十会的MIR（1）/进击的Rust生命周期——一力降十会的MIR（1）.html"><strong aria-hidden="true">2.5.</strong> 进击的Rust生命周期——一力降十会的MIR（1）</a></li><li class="chapter-item expanded "><a href="../../02_生命周期/进击的Rust生命周期——一力降十会的MIR（2）/进击的Rust生命周期——一力降十会的MIR（2）.html"><strong aria-hidden="true">2.6.</strong> 进击的Rust生命周期——一力降十会的MIR（2）</a></li><li class="chapter-item expanded "><a href="../../02_生命周期/Common_Rust_Lifetime_Misconceptions/Common_Rust_Lifetime_Misconceptions.html"><strong aria-hidden="true">2.7.</strong> Common Rust Lifetime Misconceptions</a></li><li class="chapter-item expanded "><a href="../../02_生命周期/Rust生命周期常见误区/Rust生命周期常见误区.html"><strong aria-hidden="true">2.8.</strong> 译：Rust生命周期常见误区</a></li></ol></li><li class="chapter-item expanded "><a href="../../empty.html"><strong aria-hidden="true">3.</strong> 无畏并发</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../05_无畏并发/简单写个Rust无锁队列/简单写个Rust无锁队列.html"><strong aria-hidden="true">3.1.</strong> 简单写个Rust无锁队列</a></li><li class="chapter-item expanded "><a href="../../05_无畏并发/进击的Rust多线程——混合自旋锁/进击的Rust多线程——混合自旋锁.html"><strong aria-hidden="true">3.2.</strong> 进击的Rust多线程——混合自旋锁</a></li><li class="chapter-item expanded "><a href="../../05_无畏并发/An_unsafe_tour_of_Rust's_Send_and_Sync/An_unsafe_tour_of_Rust's_Send_and_Sync.html"><strong aria-hidden="true">3.3.</strong> An unsafe tour of Rust's Send and Sync</a></li><li class="chapter-item expanded "><a href="../../05_无畏并发/进击的Rust多线程——Send与Sync/进击的Rust多线程——Send与Sync.html"><strong aria-hidden="true">3.4.</strong> 进击的Rust多线程——Send与Sync</a></li><li class="chapter-item expanded "><a href="../../05_无畏并发/进击的Rust多线程——离经叛道的PhantomData/进击的Rust多线程——离经叛道的PhantomData.html"><strong aria-hidden="true">3.5.</strong> 进击的Rust多线程——离经叛道的PhantomData</a></li><li class="chapter-item expanded "><a href="../../05_无畏并发/Rust_Async_Pin概念解析/Rust_Async_Pin概念解析.html"><strong aria-hidden="true">3.6.</strong> Rust Async: Pin概念解析</a></li><li class="chapter-item expanded "><a href="../../05_无畏并发/Rust和C++的并发库对比/Rust和C++的并发库对比.html"><strong aria-hidden="true">3.7.</strong> 译：Rust 和 C++ 的并发库对比</a></li><li class="chapter-item expanded "><a href="../../05_无畏并发/Rust原子类型和内存排序/Rust原子类型和内存排序.html"><strong aria-hidden="true">3.8.</strong> Rust原子类型和内存排序</a></li></ol></li><li class="chapter-item expanded "><a href="../../empty.html"><strong aria-hidden="true">4.</strong> 网络编程</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../06_网络编程/从编解码层面理解WebSocket_手写一个WebSocket/从编解码层面理解WebSocket_手写一个WebSocket.html"><strong aria-hidden="true">4.1.</strong> 从编解码层面理解WebSocket 手写一 个WebSocket</a></li><li class="chapter-item expanded "><a href="../../06_网络编程/透过Rust探索系统的本原：网络篇/透过Rust探索系统的本原：网络篇.html"><strong aria-hidden="true">4.2.</strong> 透过Rust探索系统的本原：网络篇</a></li></ol></li><li class="chapter-item expanded "><a href="../../empty.html"><strong aria-hidden="true">5.</strong> 轮子系列</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../07_轮子系列/700行Rust写一个内存分配器/700行Rust写一个内存分配器.html"><strong aria-hidden="true">5.1.</strong> 700行Rust写一个内存分配器</a></li><li class="chapter-item expanded "><a href="../../07_轮子系列/Rust：网络库的实现思路/Rust：网络库的实现思路.html"><strong aria-hidden="true">5.2.</strong> Rust：网络库的实现思路</a></li><li class="chapter-item expanded "><a href="../../07_轮子系列/Rust异步运行时基础部件/Rust异步运行时基础部件.html"><strong aria-hidden="true">5.3.</strong> Rust异步运行时基础部件</a></li><li class="chapter-item expanded "><a href="../../07_轮子系列/使用Rust+epoll编写异步IO框架/使用Rust+epoll编写异步IO框架（1）.html"><strong aria-hidden="true">5.4.</strong> 使用Rust+epoll编写异步IO框架（1）</a></li><li class="chapter-item expanded "><a href="../../07_轮子系列/使用Rust+epoll编写异步IO框架/使用Rust+epoll编写异步IO框架（2）.html"><strong aria-hidden="true">5.5.</strong> 使用Rust+epoll编写异步IO框架（2）</a></li><li class="chapter-item expanded "><a href="../../07_轮子系列/使用Rust+epoll编写异步IO框架/使用Rust+epoll编写异步IO框架（3）.html"><strong aria-hidden="true">5.6.</strong> 使用Rust+epoll编写异步IO框架（3）</a></li><li class="chapter-item expanded "><a href="../../07_轮子系列/用rust从零开发一套web框架/用rust从零开发一套web框架：day1.html"><strong aria-hidden="true">5.7.</strong> 用rust从零开发一套web框架：day1</a></li><li class="chapter-item expanded "><a href="../../07_轮子系列/用rust从零开发一套web框架/用rust从零开发一套web框架：day2.html"><strong aria-hidden="true">5.8.</strong> 用rust从零开发一套web框架：day2</a></li><li class="chapter-item expanded "><a href="../../07_轮子系列/用rust从零开发一套web框架/用rust从零开发一套web框架：day3.html"><strong aria-hidden="true">5.9.</strong> 用rust从零开发一套web框架：day3</a></li><li class="chapter-item expanded "><a href="../../07_轮子系列/用rust从零开发一套web框架/用rust从零开发一套web框架：day4.html"><strong aria-hidden="true">5.10.</strong> 用rust从零开发一套web框架：day4</a></li><li class="chapter-item expanded "><a href="../../07_轮子系列/用rust从零开发一套web框架/用rust从零开发一套web框架：day5.html"><strong aria-hidden="true">5.11.</strong> 用rust从零开发一套web框架：day5</a></li></ol></li><li class="chapter-item expanded "><a href="../../empty.html"><strong aria-hidden="true">6.</strong> 奇技淫巧</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../08_奇技淫巧/Copy-On-Write是不是优化？/Copy-On-Write是不是优化？.html"><strong aria-hidden="true">6.1.</strong> 译：Copy-On-Write是不是优化？</a></li><li class="chapter-item expanded "><a href="../../08_奇技淫巧/揭秘神奇的Rust_Axum风格的函数实现/揭秘神奇的Rust_Axum风格的函数实现.html"><strong aria-hidden="true">6.2.</strong> 译：揭秘神奇的 Rust Axum 风格的函数实现</a></li><li class="chapter-item expanded "><a href="../../08_奇技淫巧/“变长参数”函数与回调/“变长参数”函数与回调.html"><strong aria-hidden="true">6.3.</strong> “变长参数”函数与回调</a></li><li class="chapter-item expanded "><a href="../../08_奇技淫巧/Rust字符串格式化的幕后：format_args!()/Rust字符串格式化的幕后：format_args!().html"><strong aria-hidden="true">6.4.</strong> 译：Rust字符串格式化的幕后：format_args!()</a></li><li class="chapter-item expanded "><a href="../../08_奇技淫巧/给Rust带来一点C++特产/给Rust带来一点C++特产.html"><strong aria-hidden="true">6.5.</strong> 给Rust带来一点C++特产</a></li><li class="chapter-item expanded "><a href="../../08_奇技淫巧/一步步实现_Rust_Bevy_ECS_的_System_简化版本/一步步实现_Rust_Bevy_ECS_的_System_简化版本.html"><strong aria-hidden="true">6.6.</strong> 一步步实现 Rust Bevy ECS 的 System 简化版本</a></li><li class="chapter-item expanded "><a href="../../08_奇技淫巧/Exploring_Design_Patterns_in_Rust_with_Algorithmic_Trading_Examples/Exploring_Design_Patterns_in_Rust_with_Algorithmic_Trading_Examples.html"><strong aria-hidden="true">6.7.</strong> Exploring Design Patterns in Rust with Algorithmic Trading Examples</a></li></ol></li><li class="chapter-item expanded "><a href="../../empty.html"><strong aria-hidden="true">7.</strong> 源码分析</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../09_源码分析/Rust并发：bytes源码分析/Rust并发：bytes源码分析.html"><strong aria-hidden="true">7.1.</strong> Rust并发：bytes源码分析</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/Rust并发：标准库Arc源码分析/Rust并发：标准库Arc源码分析.html"><strong aria-hidden="true">7.2.</strong> Rust并发：标准库Arc源码分析</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/Rust并发：标准库sync_Once源码分析/Rust并发：标准库sync_Once源码分析.html"><strong aria-hidden="true">7.3.</strong> Rust并发：标准库sync::Once源码分析</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/Rust源码阅读：引用计数Rc/Rust源码阅读：引用计数Rc.html"><strong aria-hidden="true">7.4.</strong> Rust源码阅读：引用计数Rc</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/Rust源码阅读：Cell、RefCell与内部可变性/Rust源码阅读：Cell、RefCell与内部可变性.html"><strong aria-hidden="true">7.5.</strong> Rust源码阅读： Cell、RefCell与内部可变性</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/关于_Rust_的_UnsafeCell、Cell_与_RefCell/关于_Rust_的_UnsafeCell、Cell_与_RefCell.html"><strong aria-hidden="true">7.6.</strong> 关于 Rust 的 UnsafeCell、Cell 与 RefCell</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/Rust_Async_async-stream源码分析/Rust_Async_async-stream源码分析.html"><strong aria-hidden="true">7.7.</strong> Rust Async: async-stream源码分析</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/走进Tokio的异步世界/走进Tokio的异步世界.html" class="active"><strong aria-hidden="true">7.8.</strong> 走进 Tokio 的异步世界</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/tokio.rs_runtime的实现/tokio.rs_runtime的实现.html"><strong aria-hidden="true">7.9.</strong> tokio.rs runtime 的实现</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/Tokio_internals/Tokio_internals.html"><strong aria-hidden="true">7.10.</strong> Tokio internals</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/Tokio_internals/译文：Tokio內部机制.html"><strong aria-hidden="true">7.11.</strong> 译：Tokio 内部机制</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/Rust_Axum_HTTP_框架的架构分析/Rust_Axum_HTTP_框架的架构分析.html"><strong aria-hidden="true">7.12.</strong> Rust Axum HTTP 框架的架构分析</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/安利一个Rust_Game_Engine：Bevy--ECS部分/安利一个Rust_Game_Engine：Bevy--ECS部分.html"><strong aria-hidden="true">7.13.</strong> 安利一个Rust Game Engine：Bevy--ECS部分</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/Tokio_解析之任务调度/Tokio_解析之任务调度.html"><strong aria-hidden="true">7.14.</strong> Tokio 解析之任务调度</a></li></ol></li><li class="chapter-item expanded "><a href="../../empty.html"><strong aria-hidden="true">8.</strong> 生态观察</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../11_生态观察/Rust_web_frameworks_have_subpar_error_reporting/Rust_web_frameworks_have_subpar_error_reporting.html"><strong aria-hidden="true">8.1.</strong> Rust web frameworks have subpar error reporting</a></li><li class="chapter-item expanded "><a href="../../11_生态观察/SeaORM：要做Rust版本的ActiveRecord/SeaORM：要做Rust版本的ActiveRecord.html"><strong aria-hidden="true">8.2.</strong> SeaORM：要做Rust版本的ActiveRecord</a></li></ol></li><li class="chapter-item expanded "><a href="../../empty.html"><strong aria-hidden="true">9.</strong> 死灵终极</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../12_死灵终极/Learn_Rust_the_Dangerous_Way_系列文章翻译/Learn_Rust_the_Dangerous_Way_系列文章翻译_总述.html"><strong aria-hidden="true">9.1.</strong> 译：Learn Rust the Dangerous Way 总述</a></li><li class="chapter-item expanded "><a href="../../12_死灵终极/Learn_Rust_the_Dangerous_Way_系列文章翻译/Learn_Rust_the_Dangerous_Way_系列文章翻译_0.html"><strong aria-hidden="true">9.2.</strong> 译：Learn Rust the Dangerous Way 0</a></li><li class="chapter-item expanded "><a href="../../12_死灵终极/Learn_Rust_the_Dangerous_Way_系列文章翻译/Learn_Rust_the_Dangerous_Way_系列文章翻译_1.html"><strong aria-hidden="true">9.3.</strong> 译：Learn Rust the Dangerous Way 1</a></li><li class="chapter-item expanded "><a href="../../12_死灵终极/Learn_Rust_the_Dangerous_Way_系列文章翻译/Learn_Rust_the_Dangerous_Way_系列文章翻译_2.html"><strong aria-hidden="true">9.4.</strong> 译：Learn Rust the Dangerous Way 2</a></li><li class="chapter-item expanded "><a href="../../12_死灵终极/Learn_Rust_the_Dangerous_Way_系列文章翻译/Learn_Rust_the_Dangerous_Way_系列文章翻译_3.html"><strong aria-hidden="true">9.5.</strong> 译：Learn Rust the Dangerous Way 3</a></li><li class="chapter-item expanded "><a href="../../12_死灵终极/Learn_Rust_the_Dangerous_Way_系列文章翻译/Learn_Rust_the_Dangerous_Way_系列文章翻译_4.html"><strong aria-hidden="true">9.6.</strong> 译：Learn Rust the Dangerous Way 4</a></li><li class="chapter-item expanded "><a href="../../12_死灵终极/Learn_Rust_the_Dangerous_Way_系列文章翻译/Learn_Rust_the_Dangerous_Way_系列文章翻译_5.html"><strong aria-hidden="true">9.7.</strong> 译：Learn Rust the Dangerous Way 5</a></li><li class="chapter-item expanded "><a href="../../12_死灵终极/Unsafe_Rust_随堂小测/Unsafe_Rust_随堂小测（一）.html"><strong aria-hidden="true">9.8.</strong> Unsafe Rust 随堂小测（一）</a></li><li class="chapter-item expanded "><a href="../../12_死灵终极/Unsafe_Rust_随堂小测/Unsafe_Rust_随堂小测（二）.html"><strong aria-hidden="true">9.9.</strong> Unsafe Rust 随堂小测（二）</a></li><li class="chapter-item expanded "><a href="../../12_死灵终极/Unsafe_Rust_随堂小测/Unsafe_Rust_随堂小测（三）.html"><strong aria-hidden="true">9.10.</strong> Unsafe Rust 随堂小测（三）</a></li><li class="chapter-item expanded "><a href="../../12_死灵终极/Unsafe_Rust_随堂小测/Unsafe_Rust_随堂小测参考答案.html"><strong aria-hidden="true">9.11.</strong> Unsafe Rust 随堂小测参考答案</a></li></ol></li></ol>
            </div>
            <div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
        </nav>

        <div id="page-wrapper" class="page-wrapper">

            <div class="page">
                                <div id="menu-bar-hover-placeholder"></div>
                <div id="menu-bar" class="menu-bar sticky bordered">
                    <div class="left-buttons">
                        <button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
                            <i class="fa fa-bars"></i>
                        </button>
                        <button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
                            <i class="fa fa-paint-brush"></i>
                        </button>
                        <ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
                            <li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
                        </ul>
                        <button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
                            <i class="fa fa-search"></i>
                        </button>
                    </div>

                    <h1 class="menu-title">Rust 优秀博文</h1>

                    <div class="right-buttons">
                        <a href="../../print.html" title="Print this book" aria-label="Print this book">
                            <i id="print-button" class="fa fa-print"></i>
                        </a>

                    </div>
                </div>

                <div id="search-wrapper" class="hidden">
                    <form id="searchbar-outer" class="searchbar-outer">
                        <input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
                    </form>
                    <div id="searchresults-outer" class="searchresults-outer hidden">
                        <div id="searchresults-header" class="searchresults-header"></div>
                        <ul id="searchresults">
                        </ul>
                    </div>
                </div>

                <!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
                <script type="text/javascript">
                    document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
                    document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
                    Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
                        link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
                    });
                </script>

                <div id="content" class="content">
                    <main>
                        <h1 id="走进tokio的异步世界"><a class="header" href="#走进tokio的异步世界">走进Tokio的异步世界</a></h1>
<p>原文：<a href="https://zhuanlan.zhihu.com/p/346707572">https://zhuanlan.zhihu.com/p/346707572</a></p>
<p>作者：<a href="https://www.zhihu.com/people/lipiisme">lipi</a></p>
<p>Tokio 是一个基于 Rust 语言开发的异步运行时。初接触的开发者可能会存在两个疑问，为什么要异步，什么要基于 Rust 来做异步？</p>
<p>简单的说，异步更符合计算机的运行机制，能够更大的发挥计算能力。当然，这个是针对 IO 密集型的任务。如果是 CPU 密集型的，长耗时的纯计算，那还是同步机制好</p>
<p>从通常的场景来看，大部分的应用都是 IO 密集型的。长耗时的纯 CPU 计算只需要写一个脚本跑就可以了，比较简单</p>
<p>为什么采用 Rust 来做异步，这个可能要说的内容比较长。个人的理解，从 Python 的 yield 和 green thread ，到后来的 Node callback ，到 go 和 java 的异步，都实现的比较别扭，没有完全释放异步的性能。究其原因，还是因为之前的语言有自己的设计模式，只是在原有语言的能力上增加了一些语法糖来实现 Async ，没有专门针对异步来设计。通过 green thread 或者 callback 都不是异步的全部。Rust 是系统级语言，也就是底层的能力透明的使用 Linux 系统能力，也就有可能充分利用系统能力来打造完全为异步而设计的框架，Tokio 就是这么一个框架。</p>
<p>有一篇文章：<a href="https://link.zhihu.com/?target=https%3A//www.infoq.com/presentations/rust-2019/">Rust’s Journey to Async/Await</a> 讲述了 Rust Async 的历史。我在 [Rust 高性能开发](https://zhuanlan.zhihu.com/深入了解 Rust 异步开发模式 - lipi的文章 - 知乎 https://zhuanlan.zhihu.com/p/104098627) 里面也描述了这个过程：</p>
<p>Async 为什么会采用 Native Thread ，什么是 Native Thread ?</p>
<p>核心的原因是，Rust 是 &quot;system programming language&quot; ，和 C 之间不能有 overhead 。也就是说，Rust 必须使用系统 Native 的 Thread，才能和 C 的转换没有额外的 IO 损耗。</p>
<p>Rust 的 Async 采用了一种 &quot;Synchronous non-blocking network I/O&quot; （同步非阻塞IO）。这个看上去有些矛盾，但是仔细了解一下，感觉挺有道理的。同步阻塞的问题，就是效率较低。异步非阻塞的问题，对于长耗时的操作效率较低。异步阻塞，能够让长耗时的任务安排到独立线程运行，达到更好的性能。同步非阻塞IO，就是用同步的方法来写代码，但是内部其实是异步调用。</p>
<p>async-std 在<a href="https://link.zhihu.com/?target=https%3A//async.rs/blog/stop-worrying-about-blocking-the-new-async-std-runtime/">这篇博客</a> 这样说：&quot;The new runtime <strong>detects blocking</strong> automatically. We don’t need <a href="https://link.zhihu.com/?target=https%3A//docs.rs/async-std/1.2.0/async_std/task/fn.spawn_blocking.html">spawn_blocking</a> 。anymore and can simply deprecate it &quot; 。系统 runtime 竟然能够自动检测是不是阻塞操作，不需要显式调用 spawn_blocking 来针对阻塞操作。但是 Tokio 没有采用这个办法，Tokio 提供了 <a href="https://link.zhihu.com/?target=https%3A//docs.rs/tokio/1.1.0/tokio/task/fn.spawn_blocking.html">spawn_blocking</a> 来创造阻塞任务</p>
<p>但是 Native Thread 在应对 IO 请求的时候，存在问题。它会针对每个请求，准备一个线程。这样会极大消耗系统资源，并且这些线程在等待的时候什么都不做。这样的机制面对大量请求的异步操作时会非常低效。</p>
<p>Go 和 Erlang 都是采用 Green Thread 来解决这个问题。但是 Rust 因为不想和 C 之间有更多的隔阂，不想采用 Green Thread 模式。</p>
<p>Rust 参考了 Nginx 的 Event Poll 模型，还有 Node.js 的 &quot;Evented non-blocking IO&quot; 模型。withoutboats 非常推崇 Node.js 模型，但是 Node.js 带来了回调地狱 (callback hell) 。Javascript 又创造了 Promise 来避免回调的一些问题。Promise 就是 Future 的思路来源。</p>
<p>Twitter 的工程师在处理这个问题的时候，放弃了 JVM 转而用 Scala ，获得了非常大的性能提升 。然后他们写了一个 Paper 叫做 &quot;<a href="https://link.zhihu.com/?target=https%3A//monkey.org/~marius/funsrv.pdf">Your Server as a Function</a>&quot; 。介绍了一个概念，叫做 Future 。这样描述：</p>
<blockquote>
<p>A future is a container used to hold the result of an asynchronous operation such as a network RPC, a timeout, or a disk I/O operation. A future is either <em>empty</em>—the result is not yet available; <em>succeeded</em>—the producer has completed and has populated the future with the result of the operation; or <em>failed</em>—the producer failed, and the future contains the resulting exception</p>
</blockquote>
<p>Future 是一个容器用来收置一个异步操作，例如网络、RPC、超时、或者磁盘 I/O。Future 或者是空，这个时候结果还没有返回；或者是成功，生产者（ 生产Future 的函数或者进程）已经提交并且完成了 Future 的操作，获得了结果；或者失败，生产者出现了错误，future 返回了异常结果</p>
<p>Rust 在这个基础上，完善并推出了 zero cost future 。Aaron Turon 写了另外一篇文章：<a href="https://link.zhihu.com/?target=http%3A//aturon.github.io/blog/2016/08/11/futures/">Zero-cost futures in Rust </a>来详细说明这个。这应该是 Rust 语言级别对 Async Future 的优化，也是 Rust Async 的精华所在，Aaron 在里面是这样说的：</p>
<blockquote>
<p>I’ve claimed a few times that our futures library provides a zero-cost abstraction, in that it compiles to something very close to <strong>the state machine code</strong> you’d write by hand.</p>
<p>None of the future combinators impose any allocation. When we do things like chain uses of <code>and_then</code>, not only are we not allocating, we are in fact building up a big <code>enum</code> that represents the state machine. (There is one allocation needed per “task”, which usually works out to one per connection.)
When an event arrives, only one dynamic dispatch is required.
There are essentially no imposed synchronization costs; if you want to associate data that lives on your event loop and access it in a single-threaded way from futures, we give you the tools to do so.</p>
</blockquote>
<p>意思就是 Rust 设计了一个类似“状态机”的机制来优化 future 的调度。减少多层嵌套 future 的额外分配的开销；多次事件处理一次分配；提供工具在同步进程关联数据。这个挺有意思的，我们可以在下一个篇幅里面研究一下 Rust 是怎么实现的。这篇先说 Tokio</p>
<p><img src="assets/010.webp" alt="" /></p>
<p>上面是 Rust 异步调用的一个示意图，原图来自于**<a href="https://link.zhihu.com/?target=https%3A//twitter.com/_lrlna/status/1164605542897090561%3Fs%3D20">ira</a>** 。</p>
<p>Future 提交到任务执行队列(1)。执行后台是一个 event loop 和线程池。Future 提交之后，会有一个线程 poll 这个队列(2)，然后分配线程来执行 Future 。执行的时候会调用 Future 的 poll，如果发现 poll 的状态是 Ready(3)，就把返回值返回给在 await 位置等待的线程(4)。如果 poll 的状态是 Pending，则把在事件循环里面的事件树上做记录，线程继续执行 Future，主 poll 线程离开。</p>
<p>线程在执行 Future 之后，执行完成。就通过 waker 提交到事件树(5)，告诉本线程执行完成。事件循环到这个事件的时候，发现 Future 执行完成。就通过回掉 Waker(6)，把 Future 重新推送到执行队列。这个时候，Future 已经执行完成，Future 也有返回值。再次 poll 的时候，就返回结果给在 await 等待的线程</p>
<p>上面的过程有些复杂，核心包括两个：</p>
<ul>
<li>线程池和轮询分配机制</li>
<li>事件树和轮询机制</li>
</ul>
<p>可以简化理解为，后面有一堆线程。提交一个 Future 到队列。后面有个分配者(线程)分配线程池的线程来执行。分配线程只做分配，同时看队列的线程执行完成没有（通过查看 poll 状态）。</p>
<p>事件和 waker 就是查看和调度在执行 Future 的线程。一旦发现执行完成，就把执行完成的 Future 再推到执行线程，通过 poll 返回给调用者</p>
<p>所以我们还是回到 Future 的定义，以及怎么执行 Future。就可能会更清晰一些</p>
<p>Future 的定义如下：</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>pub trait Future{
  type Output;
  fn poll(self:Pin&lt;&amp;mut Self&gt;, cx:&amp;mut Context&lt;`_&gt;) -&gt; Poll&lt;Self::Output&gt;;
}
<span class="boring">}
</span></code></pre></pre>
<p>Output 是当 Future 完成之后的结果</p>
<p>poll 是一个函数，返回结果有两个。如果 Future 还没完成就返回 <code>Poll::Pending</code>；如果 Future 执行完成就返回 <code>Poll::Ready(val)</code>，val 就是具体的返回值</p>
<p>Poll 参数有两个，一个是 Pin，一个是 Context。Pin 的作用是让这个 trait 不要移动。因为移动会造成额外的开销。withoutboats 有一篇文章 <strong><a href="https://link.zhihu.com/?target=https%3A//boats.gitlab.io/blog/post/zero-cost-abstractions/">Zero Cost Abstractions</a></strong> 里面有一段说明了 Pin 的作用：</p>
<blockquote>
<p><strong>Async/await and Futures.</strong> The Futures API is an important example, because the early versions of futures hit the “zero cost” part of zero cost abstraction really well, but was not actually providing a good enough UX to drive adoption. By adding pinning to support async/await, references across awaits, and so on, we’ve made a product that I really think will solve users’ problems and make Rust more viable for writing high performance network services.</p>
</blockquote>
<p>Zero Cost Abstraction（零成本抽象） 是 Rust 设计 Zero Cost Future 的初衷。withoutboats 在上面这边文章里面引用了 C++ 设计者 Bjarne Stroustrup 的一段话作为 Zero Cost Abstract 的定义</p>
<blockquote>
<p><em>What you don’t use, you don’t pay for. And further: What you do use, you couldn’t hand code any better.</em></p>
</blockquote>
<p>这句话原始的来源于 <strong><a href="https://link.zhihu.com/?target=https%3A//www.stroustrup.com/ETAPS-corrected-draft.pdf">Foundations of C++</a></strong></p>
<p><img src="assets/020.webp" alt="" /></p>
<p>Withoutboat 描述 Pin 的设计，是提供了一种更好 UX 来支持 Async 的操作</p>
<p>poll 还有一个参数，叫做 Context，属于 waker 的一个 trait。这个也引入了另外一个概念叫 waker。在上面的异步流程图里面也可以看到，waker 是事件驱动的很关键的机制。</p>
<p>我们下面就来看看 pin 和 waker 的机制</p>
<p><code>Pin&lt;P&gt;</code> 让被 pin 的 P 所指向的内存块在内存里固定，不能被移动，在 P 被 dropped 的时候也不能清除或者分配这块内存</p>
<p>在 Async 的实现过程中，函数的执行是分段的。例如在下面的代码里面：</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>async fn foo() -&gt; u8 { 5 }

async fn bar() -&gt; impl Future&lt;Output = u8&gt; {
  let i = 1;
  let x: u8 = foo().await;
  let y = &amp;i;
  *y + x
}
<span class="boring">}
</span></code></pre></pre>
<p>在 <code>foo().await</code> 调用这里，前面的 <code>let i =1;</code> 和 await 后面执行的可能不在一个线程。那 i 的状态就需要保留。</p>
<p>程序执行的时候会保存状态到 heap 和 stack，就是堆和栈。Stack 是每个函数创建的时候会在内存有一块区域，如果这个函数退出了，对象这个区域的内容就清除；Heap 是一块集中的区域，由 rust 的编译器管理。大致示意图如下：</p>
<p><img src="assets/030.webp" alt="" /></p>
<p>上面的 async 代码，<code>let i = 1</code>，就属于某一个线程的 stack。然后到了 <code>let x: u8 = foo().await</code> 的时候，前一个线程已经结束了。那 <code>i</code> 的值就需要保持住，然后下一个线程在 <code>foo()</code> 运行完之后，可以获得借用 <code>i</code>，<code>let y = %i</code></p>
<p>上面定义的两个都是 Future，通过 <code>tokio::spawn</code> 或者 <code>#[tokio::main]</code> 运行。在运行之前，编译器会把 <code>async</code> 后面的部分解开。</p>
<pre><code class="language-text">/// Spawns a future onto the thread pool
pub(crate) fn spawn&lt;F&gt;(&amp;self, future: F) -&gt; JoinHandle&lt;F::Output&gt;
where
F: Future + Send + 'static,
F::Output: Send + 'static,
{
  let (task, handle) = task::joinable(future);
  self.shared.schedule(task, false);
  handle
} 
</code></pre>
<p><code>joinable</code> 是把 future 包装为一个 RawTask 和一个 包裹着RawTask 的 JoinHandle，如下：</p>
<pre><code class="language-text">pub(crate) fn joinable&lt;T, S&gt;(task: T) -&gt; (Notified&lt;S&gt;, JoinHandle&lt;T::Output&gt;)
where
T: Future + Send + 'static,
S: Schedule,
{
  let raw = RawTask::new::&lt;_, S&gt;(task);

  let task = Task {
    raw,
    _p: PhantomData,
  };

  let join = JoinHandle::new(raw);

  (Notified(task), join)
}
</code></pre>
<p>task 就可以进入队列来调度，Spawn 的返回值是 JoinHandle 类型。JoinHandle 是对线程的协作管理。因为 Future 的执行就是嵌套循环的执行 <code>poll</code>，调用 <code>poll</code>，发现数据 Ready，就执行返回；发现数据 Pending，就再推送到队列等待下次 poll</p>
<p>如果在一个 task 做了一个阻塞或者长耗时的操作而没有通过 <code>.await</code> 提交到其他线程，那就会阻塞这个线程，然后后面的任务就无法执行</p>
<p>所以 tokio 设置了一个 Budget 的机制，Budget 标记了一个 task 可以执行的一个阈值，默认是 128</p>
<p>回到前面， spawn 的时候，返回了一个 JoinHandle 的实例，针对 spawn 的 future。在程序开始执行的时候，就会执行这个 实例的 <code>poll()</code>。JoinHandle 的 poll 函数是这样：</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>fn poll(self: Pin&lt;&amp;mut Self&gt;, cx: &amp;mut Context&lt;'_&gt;) -&gt; Poll&lt;Self::Output&gt; {
  let mut ret = Poll::Pending;

  // Keep track of task budget
  let coop = ready!(crate::coop::poll_proceed(cx));
  
	// read task output
  unsafe {
    raw.try_read_output(&amp;mut ret as *mut _ as *mut (), cx.waker());
  }

  if ret.is_ready() {
    coop.made_progress();
  }

  ret
}
<span class="boring">}
</span></code></pre></pre>
<p><code>crate::coop::poll_proceed(cx)</code> 的作用是递减 coop 的 budget ，就是上面说的默认 128 。如果递减 budget ，发现 budget 为 0 ，也就是这个 task 执行时间较长了。那就需要把这个任务重新标记投入到任务队列，释放这个线程</p>
<p>那这个时间间隔是多少呢？budget 定为 128 ，也就是执行 128 个poll 循环之后，发现任务还没完成，就再打包投入到任务队列</p>
<p>异步架构对于长耗时阻塞的处理是一个难点。写代码的时候，很难完全预知哪些任务会阻塞。但是，一旦有一个任务耗时很久，就会导致整个 poll 阻塞</p>
<p><img src="assets/040.webp" alt="" /></p>
<p>tokio 采用了一种没有 Global 的 poll 方式。每个 spawned task 处理自己的 future。长耗时任务不会占用主线程。</p>
<p>有一篇文章：<strong><a href="https://link.zhihu.com/?target=https%3A//ryhl.io/blog/async-what-is-blocking/">Async：what is the blocking?</a></strong>，描述了 Tokio 的这个 coop 的机制。就像本文最开始说的， tokio 还提供了 spawn_blocking 函数来固定一个线程执行长耗时任务。因为 task 上下文的来回切换和调度也会耗费时间，如果 cpu 核数够用的话，可以固定一些线程执行长耗时任务。Tokio 提供了一种灵活内部机制避免长耗时任务降低框架性能，也提供了手工的执行长耗时任务的函数，这样的做法比较人性化。</p>
<p>前面插入了一段关于线程协作机制，让我们继续看 spawn task：</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>let (task, handle) = task::joinable(future);
self.shared.schedule(task, false);
handle
<span class="boring">}
</span></code></pre></pre>
<p>spawn 把 future 包装成 task，然后 schedule ，返回一个 JoinHandle。在 poll 开始运行的时候，JoinHandle 会查看 Budget 资源，同时尝试获取任务输出，如果任务还没完成。就更新 Waker ，标记 task 还没完成。如果发现任务完成，就返回结果</p>
<p>在前面的调度过程中，<code>coop::poll_processed</code> 对 budget 资源不足的时候，需要讲 task yield 到等待的任务线程。如下：</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>pub(crate) fn poll_proceed(cx: &amp;mut Context&lt;'_&gt;) -&gt; Poll&lt;RestoreOnPending&gt; {
  CURRENT.with(|cell| {
    let mut budget = cell.get();

    if budget.decrement() {
      let restore = RestoreOnPending(Cell::new(cell.get()));
      cell.set(budget);
      Poll::Ready(restore)
    } else {
      cx.waker().wake_by_ref();
      Poll::Pending
    }
  })
}
<span class="boring">}
</span></code></pre></pre>
<p>调度是异步操作里面最核心的内容，Tokio 通过 Task、Cell、Waker、Scheduler、JoinHandler 等组件来实现独特的异步调度。让我们从 Task 开始，看看 Tokio 是怎么做的</p>
<p><img src="assets/050.webp" alt="" /></p>
<p>Task 结构里面是一个 RawTask，RawTask 里面是一个 Header</p>
<p>Cell 是包含了 Task 所有组件的结构，包含 header、core 和 trailer。header 是 &quot;Hot Task&quot; 的状态数据，也就是提交但还没有执行完的数据（待确认）；core 包含 task 对应的 future 以及 task 的 Scheduler（调度）；trailer 是 “Cold data”，也就是已经执行完，等待获取的 Waker</p>
<p>回顾一下产生 Task 的过程：</p>
<p><img src="assets/060.webp" alt="" /></p>
<p>通过 spawn 把带有 async 注解的代码块包裹成 Future， 然后通过 <code>RawTask::new</code> 和 Task 构造函数生成为一个 Task 的实例。然后通过 <code>JoinHandle::new</code>生成 JoinHandle；另外 Task 经过 Notified 包裹之后，通过 <code>scheduler</code>，提交到 Header 类型的任务信息队列</p>
<p>这是在程序编译器生成的过程。在 tokio 程序运行起来后，就会获取 task，然后执行 task 的 <code>poll</code>，就是上面描述过的运行的流程。再具体一些，就是下图：</p>
<p><img src="assets/070.webp" alt="" /></p>
<p>这里面有两个核心，一个是 Cell、一个是 VTable</p>
<p>VTable 是一个包含了 future 操作的函数结构体。poll 就对应 poll；dealloc 代表释放内存；try_read_output 代表尝试读取 future 的 output；drop_join_handle_slow 代表清除 JoinHandle；shutdown 代表停止 scheduler</p>
<p>RawTask 实现了对应上面的 5 种操作，例如：</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>impl RawTask{
  // ...
  pub(super) fn poll(self) {
    let vtable = self.header().vtable;
    unsafe { (vtable.poll)(self.ptr) }
  }
}
<span class="boring">}
</span></code></pre></pre>
<p>所以，当程序运行起来，获取 task ，然后运行 task 的 poll 。 就回去 Cell 找到对应 task 的 Header ，然后获取 Header 对应 VTable</p>
<p>Harness 是一个包裹 Cell 的结构。每次在进行 poll 和其他操作的时候。都会通过 Header 生成一个 Harness 的实例，然后再执行对应操作。例如：</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>unsafe fn poll&lt;T: Future, S: Schedule&gt;(ptr: NonNull&lt;Header&gt;) {
    let harness = Harness::&lt;T, S&gt;::from_raw(ptr);
    harness.poll();
}
<span class="boring">}
</span></code></pre></pre>
<p>因为 Header 对应的 VTable 是虚函数，只有实例化之后才行执行</p>
<p>在 Harness 获取 Task 的 Header 之后，开始执行 poll 的时候，会生成一个 Waker</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// harness.rs,poll()--&gt; poll_inner()
let waker_ref = waker_ref::&lt;T, S&gt;(self.header());
let cx = Context::from_waker(&amp;*waker_ref);
poll_future(self.header(), &amp;self.core().stage, snapshot, cx)
<span class="boring">}
</span></code></pre></pre>
<p>然后带着 waker 进入 <code>poll_future</code>：</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// harness.rs poll_future()

let res = guard.core.poll(cx);
// prevent the guard from dropping the future
mem::forget(guard);
<span class="boring">}
</span></code></pre></pre>
<p>在 <code>core.poll</code> 里面：</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// core.rs poll()
let future = match unsafe { &amp;mut *ptr } {
  Stage::Running(future) =&gt; future,
  _ =&gt; unreachable!(&quot;unexpected stage&quot;),
};

// Safety: The caller ensures the future is pinned.
let future = unsafe { Pin::new_unchecked(future) };

future.poll(&amp;mut cx)
<span class="boring">}
</span></code></pre></pre>
<p>上面两段可以看到，提交 Future 的时候用 Guard 包裹，并且调用 <code>mem:forget</code> ，在这段程序执行完成之后，future 还保留。然后在 <code>core.poll</code> 的时候，使用了 <code>Pin</code> 方法固定了 future 的内存位置，这个在上面描述过。关于 Pin 和自引用结构，可以看这两篇文章： <strong><a href="https://link.zhihu.com/?target=https%3A//folyd.com/blog/rust-pin-unpin/%23pindao-zhan-shang">Rust的Pin与Unpin</a></strong> 和 <strong><a href="https://zhuanlan.zhihu.com/p/346707572/edit">Pin 概念解析</a></strong></p>
<blockquote>
<p>如果不想让一个 <code>T</code>类型的实例移动，只需要把它分配在堆上，用智能指针(如 <code>Box&lt;T&gt;</code>)访问就行了， 因为移动 <code>Box&lt;T&gt;</code>只是memcpy了指针，原对象并没有被移动。不过由于 <code>Box</code>提供的api中可以获取到 <code>&amp;mut T</code>,进而可以通过 <code>mem::swap</code>间接将T移出。 所以只需要提供一个弱化版的智能指针api，防止泄露 <code>&amp;mut T</code>就能够达到防止对象被移动。这就是实现 <code>Pin</code> api的主要思路。</p>
</blockquote>
<p>在上面的过程中，Harness 又引入了一个新的概念 waker。 在 Harness 创建了 Waker，然后带入到 future 的 poll 里面。Future 是 Rust stdlib，所以 Waker 也是 Rust 异步的一个重要概念</p>
<p>回到前面构建 Waker 的过程：</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// harness.rs,poll()--&gt; poll_inner()
let waker_ref = waker_ref::&lt;T, S&gt;(self.header());
let cx = Context::from_waker(&amp;*waker_ref);
poll_future(self.header(), &amp;self.core().stage, snapshot, cx)
<span class="boring">}
</span></code></pre></pre>
<p>Waker 通过 Header 构建，Header 的结构除了任务的状态、队列信息之外，就是一个 VTable ，在上面的图里有描述。</p>
<p>那 Waker 的结构是怎么样呢，Waker 包裹了一个 RawWaker，结构如下：</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>pub struct RawWaker {
    /// A data pointer, which can be used to store arbitrary data as required
    /// by the executor.
    data: *const (),
    /// Virtual function pointer table that customizes the behavior of this waker.
    vtable: &amp;'static RawWakerVTable,
}
<span class="boring">}
</span></code></pre></pre>
<p>Waker 包含一个 data 指针和一个 RawWakerVTable。RawWakerVTable 包含四个虚函数，clone、waker、wake_by_ref 和 drop</p>
<p>Waker 是对 Future 的一个数据和操作的包装，在 poll 的过程中被传递或引用。用来实现对 Future 的管理。例如在上面 <code>coop::poll_process</code> 函数，就通过 <code>cx.waker().wake_by_ref();</code> 来获取 waker 并执行 waker 对应的函数实现协作调度：</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>pub fn wake_by_ref(&amp;self) {
  unsafe { (self.waker.vtable.wake_by_ref)(self.waker.data) }
}
<span class="boring">}
</span></code></pre></pre>
<p>在 Tokio 的异步调用过程中，有很多地方，甚至是贯穿全流程的都使用 Waker。所以 Waker 和 Poll 可以说是 Tokio 异步调用的两个核心概念，掌握了这两个概念，主干就找到了</p>
<p>Tokio 还有很多概念，一篇文章只能描述很少的部分。主要目的是自己做个记录，把对 Tokio 的一个浅显理解写出来。Tokio 应该会是异步框架的卓越代表，异步在解决了回掉地狱、阻塞处理以及基础生态库异步化改造之后，应该会在应用层带来极大的发展</p>
<p>编辑于 2021-01-31 22:16</p>

                    </main>

                    <nav class="nav-wrapper" aria-label="Page navigation">
                        <!-- Mobile navigation buttons -->
                            <a rel="prev" href="../../09_源码分析/Rust_Async_async-stream源码分析/Rust_Async_async-stream源码分析.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
                                <i class="fa fa-angle-left"></i>
                            </a>

                            <a rel="next" href="../../09_源码分析/tokio.rs_runtime的实现/tokio.rs_runtime的实现.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
                                <i class="fa fa-angle-right"></i>
                            </a>

                        <div style="clear: both"></div>
                    </nav>
                </div>
            </div>

            <nav class="nav-wide-wrapper" aria-label="Page navigation">
                    <a rel="prev" href="../../09_源码分析/Rust_Async_async-stream源码分析/Rust_Async_async-stream源码分析.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
                        <i class="fa fa-angle-left"></i>
                    </a>

                    <a rel="next" href="../../09_源码分析/tokio.rs_runtime的实现/tokio.rs_runtime的实现.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
                        <i class="fa fa-angle-right"></i>
                    </a>
            </nav>

        </div>




        <script type="text/javascript">
            window.playground_copyable = true;
        </script>


        <script src="../../elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="../../mark.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="../../searcher.js" type="text/javascript" charset="utf-8"></script>

        <script src="../../clipboard.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="../../highlight.js" type="text/javascript" charset="utf-8"></script>
        <script src="../../book.js" type="text/javascript" charset="utf-8"></script>

        <!-- Custom JS scripts -->


    </body>
</html>
